<!doctype html>
<html lang="en">
	<head>
		<title>JavaScript Patterns</title>
		<meta charset="utf-8">
	</head>
	<body>
		<script>
			/* Title: Currying
			 Description: used to create new functions dynamically by partially applying a set of arguments
			 */

			/***
			 function application
			 ***/
			// define a function
			var sayHi = function (who) {
				return "Hello" + (who ? ", " + who : "") + "!";
			};

			// invoke a function
			sayHi(); // "Hello!"
			sayHi('world'); // "Hello, world!"

			// apply a function
			sayHi.apply(null, ["hello"]); // "Hello, hello!"

			var alien = {
				sayHi:function (who) {
					return "Hello" + (who ? ", " + who : "") + "!";
				}
			};

			alien.sayHi('world'); // "Hello, world!"
			sayHi.apply(alien, ["humans"]); // "Hello, humans!"

			// the second is more efficient, saves an array
			sayHi.apply(alien, ["humans"]); // "Hello, humans!"
			sayHi.call(alien, "humans"); // "Hello, humans!"

			/***
			 partial application
			 ***/

			// for illustration purposes
			// not valid JavaScript

			// we have this function
			function add(x, y) {
				return x + y;
			}

			// and we know the arguments
			add(5, 4);

			// step 1 -- substitute one argument
			function add(5, y) {
				return 5 + y;
			}

			// step 2 -- substitute the other argument
			function add(5, 4) {
				return 5 + 4;
			}

			/***
			 currying
			 ***/

			// a curried add()
			// accepts partial list of arguments
			function add(x, y) {
				var oldx = x, oldy = y;
				if (typeof oldy === "undefined") { // partial
					return function (newy) {
						return oldx + newy;
					}
				}
				// full application
				return x + y;
			}

			// test
			typeof add(5); // "function"
			add(3)(4); // 7

			// create and store a new function
			var add2000 = add(2000);
			add2000(10); // 2010

			function schonfinkelize(fn) {
				var slice = Array.prototype.slice,
						stored_args = slice.call(arguments, 1);
				return function () {
					var new_args = slice.call(arguments),
							args = stored_args.concat(new_args);
					return fn.apply(null, args);
				};
			}

			// reference
			// http://www.jspatterns.com/
			// http://shop.oreilly.com/product/9780596806767.do?sortby=publicationDate

			// Here's a generic curry function (from kybernetikos):
			// It's slightly more complex than the common examples of currying (e.g. the one above), but that's because
			//    the function can afterwards be called either in the normal way, or in the curried way.
			//    If you call a 3 argument curried function with it, the returned function *is also curried*.
			//    e.g. you can write func(arg1)(arg2)(arg3) or func(arg1, arg2, arg3) or func(arg1)(arg2, arg3) etc...

			/* the curry procedure needs to know how many arguments are required before it should calculate the result */
			function curry(func, minArgs) {
				if (minArgs == undefined) {
					minArgs = 1;
				}

				function funcWithArgsFrozen(frozenargs) {
					return function () {
						// could do an optimisation here - if called with no arguments
						// return exactly this function.
						var args = Array.prototype.slice.call(arguments);
						var newArgs = frozenargs.concat(args);
						if (newArgs.length >= minArgs) {
							return func.apply(this, newArgs);
						} else {
							return funcWithArgsFrozen(newArgs);
						}
					};
				}

				return funcWithArgsFrozen([]);
			}

			/* Here are some example uses - I use these with a functional immutable list structure implemented in js
			 but they also work ok for normal higher order functions over arrays.
			 */

			var plus = curry(function () {
				var result = 0;
				for (var i = 0; i < arguments.length; ++i) {
					result += arguments[i];
				}
				return result;
			}, 2);

			/* Now you can call
			 plus(3,2)         // normal call
			 plus(3)           // partial application (returns a function that adds 3 to its argument)
			 plus(3)(2)        // complete application (returns 5)
			 plus()(3)()()(2)  // returns 5
			 plus(3, 2, 4, 5)  // the normal call can optionally take more than the minimum number of arguments
			 plus(3)(2, 3, 5)  // the last application can too.
			 */

			var minus = curry(function (x) {
				var result = x;
				for (var i = 1; i < arguments.length; ++i) {
					result -= arguments[i];
				}
				return result;
			}, 2);

			/* flip switches the order of the first two arguments on a function.  It is curried itself and
			 the function it returns is curried too.  Particularly useful if you want a function that subtracts a number */

			var flip = curry(function (func) {
				return curry(function (a, b) {
					return func(b, a);
				}, 2);
			});

			/* for example
			 minus(5)             // returns a function that takes its argument away from 5
			 flip(minus)(5)       // returns a function that takes 5 away from its argument
			 */
		</script>
	</body>
</html>
